#pragma once
#include <memory>
#include "Any.hpp"
#include "Buffer.hpp"
#include "Socket.hpp"
#include "Channel.hpp"
#include "EventLoop.hpp"

class Connection;
// DISCONECTED -- 连接关闭状态；   CONNECTING -- 连接建立成功-待处理状态
// CONNECTED -- 连接建立完成，各种设置已完成，可以通信的状态；  DISCONNECTING -- 待关闭状态
typedef enum
{
    DISCONNECTED,
    CONNECTING,
    CONNECTED,
    DISCONNECTING
} ConnStatu;
using PtrConnection = std::shared_ptr<Connection>;
class Connection : public std::enable_shared_from_this<Connection>
{
private:
    uint64_t _conn_id;             // 连接的唯一ID，便于连接的管理和查找
    int _sockfd;                   // 连接关联的文件描述符
    bool _enable_inactive_release; // 连接是否启动非活跃销毁的判断标志，默认为false
    EventLoop *_loop;              // 连接所关联的一个EventLoop
    ConnStatu _statu;              // 连接状态
    Socket _socket;                // 套接字操作管理
    Channel _channel;              // 连接的事件管理
    Buffer _in_buffer;             // 输入缓冲区---存放从socket中读取到的数据
    Buffer _out_buffer;            // 输出缓冲区---存放要发送给对端的数据
    Any _context;                  // 请求的接收处理上下文

    /*这四个回调函数，是让服务器模块来设置的（其实服务器模块的处理回调也是组件使用者设置的）*/
    /*换句话说，这几个回调都是组件使用者使用的*/
    using ConnectedCallback = std::function<void(const PtrConnection &)>;
    using MessageCallback = std::function<void(const PtrConnection &, Buffer *)>;
    using ClosedCallback = std::function<void(const PtrConnection &)>;
    using AnyEventCallback = std::function<void(const PtrConnection &)>;
    ConnectedCallback _connected_callback;
    MessageCallback _message_callback;
    ClosedCallback _closed_callback;
    AnyEventCallback _event_callback;
    /*组件内的连接关闭回调--组件内设置的，因为服务器组件内会把所有的连接管理起来，一旦某个连接要关闭*/
    /*就应该从管理的地方移除掉自己的信息*/
    ClosedCallback _server_closed_callback;

    /*五个channel的事件回调函数*/
    // 描述符可读事件触发后调用的函数，接收socket数据放到接收缓冲区中，然后调用_message_callback
    void HandleRead()
    {
        char buf[65535] = {0};
        ssize_t ret = _socket.NonBlockRecv(buf, 65535);
        if (ret < 0)
        {
            ShutdownInLoop();
            return;
        }
        _in_buffer.Write(buf, ret);
        if (_in_buffer.HasDataRead())
        {
            _message_callback(shared_from_this(), &_in_buffer);
        }
    }

    // 描述符可写事件触发后调用的函数，将发送缓冲区中的数据进行发送
    void HandleWrite()
    {
        ssize_t ret = _socket.NonBlockSend(_out_buffer.ReadBegin(), _out_buffer.ReadAbleSize());
        if (ret < 0)
        {
            // 发送错误, 关闭连接
            if (_in_buffer.HasDataRead())
            {
                _message_callback(shared_from_this(), &_in_buffer);
            }
            Release();
        }
        _out_buffer.ConfirmReadSize(ret);
        // 如无待发送数据则关闭写事件
        if (_out_buffer.ReadAbleSize() == 0)
        {
            _channel.DisableWrite();
            if (_statu == DISCONNECTING)
                Release();
        }
    }

    // 描述符触发挂断事件
    void HandleClose()
    {
        if (_in_buffer.HasDataRead())
        {
            _message_callback(shared_from_this(), &_in_buffer);
        }
        Release();
    }

    void HandleError()
    {
        HandleClose();
    }

    // 描述符触发任意事件: 1. 刷新连接的活跃度--延迟定时销毁任务；  2. 调用组件使用者的任意事件回调
    void HandleEvent()
    {
        if (_enable_inactive_release)
            _loop->TimerRefresh(Id());
        if (_event_callback)
            _event_callback(shared_from_this());
    }

    // 连接建立就绪后，1. 修改连接状态；  2. 启动读事件监控；  3. 调用回调函数
    void EstablishedInLoop()
    {
        assert(_statu == CONNECTING);
        _statu = CONNECTED;
        if (!_channel.IsReadable())
            _channel.EnableRead();
        if (_connected_callback)
            _connected_callback(shared_from_this());
    }

    // 发送数据，将数据放到发送缓冲区，启动写事件监控
    // void SendInLoop(const Buffer &&buf)
    // {
    //     if (_statu == DISCONNECTED)
    //         return;
    //     _out_buffer.Write(buf);
    //     if (!_channel.IsWriteable())
    //         _channel.EnableWrite();
    // }

    void SendInLoop(const char *data, size_t len)
    {
        if (_statu == DISCONNECTED)
            return;
        _out_buffer.Write(data, len);
        if (!_channel.IsWriteable())
            _channel.EnableWrite();
    }
    // 提供给组件使用者的关闭接口--并不实际关闭，需要判断有没有数据待处理
    void ShutdownInLoop()
    {
        _statu = DISCONNECTING;
        if (_in_buffer.HasDataRead())
        {
            _message_callback(shared_from_this(), &_in_buffer);
        }

        if (_out_buffer.HasDataRead())
        {
            if (!_channel.IsWriteable())
                _channel.EnableWrite();
        }
        if (!_out_buffer.HasDataRead())
        {
            Release();
        }
    }
    void ReleaseInLoop()
    {
        // 1. 修改连接状态
        _statu = DISCONNECTED;
        // 2. 移除连接的事件监控
        _channel.Remove();
        // 3. 关闭描述符
        _socket.Close();
        // 4. 如果当前定时器队列中还有定时销毁任务，则取消任务
        if (_loop->HasTimer(_conn_id))
            _loop->TimerCancal(_conn_id);
        // 5. 调用关闭回调函数
        if (_closed_callback)
            _closed_callback(shared_from_this());
        if (_server_closed_callback)
            _server_closed_callback(shared_from_this());
        // _socket.Close();
    }
    // 启动非活跃销毁，并定义多长时间无通信就是非活跃，添加定时任务
    void EnableInactiveReleaseInLoop(int sec)
    {
        _enable_inactive_release = true;
        if (_loop->HasTimer(_conn_id))
            _loop->TimerRefresh(_conn_id);
        else
            _loop->TimerAdd(_conn_id, std::bind(&Connection::Release, this), sec);
    }
    // 取消非活跃销毁
    void CancelInactiveReleaseInLoop()
    {
        _enable_inactive_release = false;
        if (_loop->HasTimer(_conn_id))
            _loop->TimerCancal(_conn_id);
    }
    // 切换协议---重置上下文以及阶段性回调处理函数 -- 而是这个接口必须在EventLoop线程中立即执行
    // 防备新的事件触发后，处理的时候，切换任务还没有被执行--会导致数据使用原协议处理了。
    void UpgradeInLoop(const Any &context, const ConnectedCallback &conn, const MessageCallback &msg,
                       const ClosedCallback &closed, const AnyEventCallback &event)
    {
        _context = context;
        _connected_callback = conn;
        _message_callback = msg;
        _closed_callback = closed;
        _event_callback = event;
    }

public:
    Connection(uint64_t conn_id, int sockfd, EventLoop *loop)
        : _conn_id(conn_id), _sockfd(sockfd), _enable_inactive_release(false), _loop(loop),
          _statu(CONNECTING), _socket(_sockfd), _channel(_loop, _sockfd)
    {
        _channel.SetReadCallback(std::bind(&Connection::HandleRead, this));
        _channel.SetCloseCallback(std::bind(&Connection::HandleClose, this));
        _channel.SetErrorCallback(std::bind(&Connection::HandleError, this));
        _channel.SetEventCallback(std::bind(&Connection::HandleEvent, this));
        _channel.SetWriteCallback(std::bind(&Connection::HandleWrite, this));
    }
    ~Connection() {}

    // 获取连接ID
    uint64_t Id() { return _conn_id; }
    // 获取管理的文件描述符
    int Fd() { return _sockfd; }
    // 是否处于CONNECTED状态
    bool Connected() { return (_statu == CONNECTED); }
    // 设置上下文--连接建立完成时进行调用
    void SetContext(const Any &context) { _context = context; }
    // 获取上下文，返回的是指针
    Any *GetContext() { return &_context; }

    // 回调函数设置
    void SetConnectedCallback(const ConnectedCallback &cb) { _connected_callback = cb; }
    void SetMessageCallback(const MessageCallback &cb) { _message_callback = cb; }
    void SetClosedCallback(const ClosedCallback &cb) { _closed_callback = cb; }
    void SetAnyEventCallback(const AnyEventCallback &cb) { _event_callback = cb; }
    void SetSrvClosedCallback(const ClosedCallback &cb) { _server_closed_callback = cb; }

    // 连接建立就绪后，进行channel回调设置，启动读监控，调用_connected_callback
    void Established()
    {
        _loop->RunInLoop(std::bind(&Connection::EstablishedInLoop, this));
    }
    // 发送数据，将数据放到发送缓冲区，启动写事件监控
    void Send(const char *data, size_t len)
    {
        // Buffer buf;
        // buf.Write(data, len);
        _loop->RunInLoop(std::bind(&Connection::SendInLoop, this, data, len));
    }
    // 提供给组件使用者的关闭接口--并不实际关闭，需要判断有没有数据待处理
    void Shutdown()
    {
        _loop->RunInLoop(std::bind(&Connection::ShutdownInLoop, this));
    }
    void Release()
    {
        _loop->RunInLoop(std::bind(&Connection::ReleaseInLoop, this));
    }
    // 启动非活跃销毁，并定义多长时间无通信就是非活跃，添加定时任务
    void EnableInactiveRelease(int sec)
    {
        _loop->RunInLoop(std::bind(&Connection::EnableInactiveReleaseInLoop, this, sec));
    }
    // 取消非活跃销毁
    void CancelInactiveRelease()
    {
        _loop->RunInLoop(std::bind(&Connection::CancelInactiveReleaseInLoop, this));
    }
    // 切换协议---重置上下文以及阶段性回调处理函数 -- 而是这个接口必须在EventLoop线程中立即执行
    // 防备新的事件触发后，处理的时候，切换任务还没有被执行--会导致数据使用原协议处理了。
    void Upgrade(const Any &context, const ConnectedCallback &conn, const MessageCallback &msg,
                 const ClosedCallback &closed, const AnyEventCallback &event)
    {
        assert(_loop->IsInLoop());
        _loop->RunInLoop(std::bind(&Connection::UpgradeInLoop, this, context, conn,
                                   msg, closed, event));
    }
};